package be.stijn.gdocs.services;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import be.stijn.gdocs.GDocsService;

import com.google.gdata.client.docs.DocsService;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.data.docs.DocumentListEntry;
import com.google.gdata.data.docs.DocumentListFeed;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;

public class GDocsServiceImpl implements GDocsService {

    private final DocsService service = new DocsService("stijn-gds-v0.0.1");
    private final SpreadsheetService spreadSheetService = new SpreadsheetService("stijn-gds-v0.0.1");
    private final DownloadService downloadService = new DownloadService(service, spreadSheetService);
    private final UploadService uploadService = new UploadService(service);
    private final Logger logger = LoggerFactory.getLogger(GDocsServiceImpl.class);

    /**
     * {@inheritDoc}
     */
    @Override
    public void login(String user, String password) throws AuthenticationException {
        logger.debug("Logging in using your google account...\n");
        service.setUserCredentials(user, password);
        spreadSheetService.setUserCredentials(user, password);
        logger.debug("Login succesfull!\n");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setProxy(String host, String port) {
        System.setProperty("http.proxyHost", host);
        System.setProperty("http.proxyPort", port);
        System.setProperty("https.proxyHost", host);
        System.setProperty("https.proxyPort", port);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setProxy(String host, String port, String user, String password) {
        setProxy(host, port);
        // Set username and password.
        String encoded = new String(Base64.encodeBase64(new String(user + ":" + password).getBytes()));
        String base64encodedCredentials = "Basic " + encoded;
        service.getRequestFactory().setPrivateHeader("Proxy-Authorization", base64encodedCredentials);
        spreadSheetService.getRequestFactory().setPrivateHeader("Proxy-Authorization", base64encodedCredentials);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void getFiles(File targetFolder) throws IOException, ServiceException {
        logger.debug("Getting Documents entries...\n");

        DocumentListFeed resultFeed = service.getFeed(new URL("https://docs.google.com/feeds/default/private/full"),
                DocumentListFeed.class);
        List<DocumentListEntry> entries = resultFeed.getEntries();
        logger.trace(String.format("Found %s entries.", entries.size()));
        for (int i = 0; i < entries.size(); i++) {
            DocumentListEntry entry = entries.get(i);
            String folder = getFolderString(entry);
            logger.trace("\t" + " [" + entry.getType() + "] " + folder + entry.getTitle().getPlainText());

            downloadService.download(entry, targetFolder.getAbsolutePath() + "/" + folder);

        }

        logger.debug("\n \n Finished downloading files!");
    }

    // TODO Search for a faster method!
    private String getFolderString(DocumentListEntry entry) throws MalformedURLException, IOException, ServiceException {
        if (entry.getParentLinks() != null && entry.getParentLinks().size() > 0) {
            DocumentListEntry f = service.getEntry(new URL(entry.getParentLinks().get(0).getHref()),
                    DocumentListEntry.class);
            String result = getFolderString(f);
            if ("".equals(result)) {
                return f.getTitle().getPlainText() + "/";
            }
            return result + f.getTitle().getPlainText() + "/";
        }
        return ""; // Using "" iso null gives you a cleaner string when there is no parent folder.
    }

    @Override
    public void uploadFiles(File file) throws IOException, ServiceException {
        uploadFiles(file, file);
    }

    private void uploadFiles(File file, File root) throws IOException, ServiceException {
        if (file == null) {
            logger.debug("File cannot be null");
            return;
        }
        // TODO handle empty directories
        if (!file.exists()) {
            logger.debug("Cannot locate the directory " + file.getAbsoluteFile());
            return;
        }

        if (!file.isDirectory()) {
            uploadService.upload(new SyncFile(file, root)); // TODO move usage of syncFile up
            return;
        }

        if (file.listFiles() != null || file.listFiles().length != 0) {
            // upload files inside the directory
            for (File f : file.listFiles()) {
                uploadFiles(f, root);
            }
        }
    }

}
